package stringx

import (
	"math"
	"regexp"
	"strings"
	"unicode"
)

// CamelToUnderline 驼峰 to 下划线
func CamelToUnderline(target string) string {
	return strings.Join(SplitUpper(target), "_")
}

// UnderlineToCamel 下划线 to 驼峰
func UnderlineToCamel(target string) string {
	arr := strings.Split(target, "_")
	for i, val := range arr {
		arr[i] = UpperFirst(val)
	}
	return strings.Join(arr, "")
}

// 清楚空白的地方，包括空格，换行符，tab等
func CleanSpace(str string) string {
	str = strings.ReplaceAll(str, " ", "")
	str = strings.ReplaceAll(str, "\t", "")
	str = strings.ReplaceAll(str, "\n", "")
	str = strings.ReplaceAll(str, "\r", "")
	return str
}

// Reverse 翻转字符串
func Reverse(str string) string {
	l := len(str)
	b := make([]byte, l)
	for i, val := range []byte(str) {
		b[l-i-1] = val
	}
	return string(b)
}

// SplitUpper 按照大小写分组
func SplitUpper(target string) []string {
	chars := []byte(target)
	result := []string{}
	str := ""
	for i := 0; i < len(target); i++ {
		char := chars[i]
		if i == 0 {

		} else if char >= 65 && char <= 90 {
			result = append(result, str)
			str = ""
		}

		str += string(char)
	}

	result = append(result, str)
	return result
}

// SplitLast 获取字符串被"."分离后的字符串数组中
// ，最后一个字符串。
func SplitFirst(str string, sep string) string {
	strArr := strings.Split(str, sep)
	if strArr != nil && len(strArr) > 0 {
		return strArr[0]
	}

	return ""
}

func SplitFirstArray(str string, sep string) (first string, next string) {
	strArr := strings.Split(str, sep)
	if strArr != nil && len(strArr) > 0 {
		first = strArr[0]
		lastArr := strArr[1:len(strArr)]
		next = strings.Join(lastArr, sep)
		return
	}

	return str, ""
}

// SplitLast 获取字符串被"."分离后的字符串数组中
// ，最后一个字符串。
func SplitLast(str string, sep string) string {
	strArr := strings.Split(str, sep)
	if strArr != nil && len(strArr) > 0 {
		return strArr[len(strArr)-1]
	}

	return str
}

// SplitPrevLast 获取字符串被"."分离后的字符串数组中
// ，最后一个字符串。
func SplitPrevLast(str string, sep string) (prev string, last string) {
	strArr := strings.Split(str, sep)
	if strArr != nil && len(strArr) > 0 {
		last = strArr[len(strArr)-1]
		prevArr := strArr[:len(strArr)-1]
		prev = strings.Join(prevArr, sep)
		return
	}

	return "", str
}

// IsLowerFirst 首字母是否小写
func IsLowerFirst(str string) bool {
	first := str[0]
	if first >= 97 && first <= 122 {
		return true
	}
	return false
}

// IsUpperFirst 首字母是否大写
func IsUpperFirst(str string) bool {
	first := str[0]
	if first >= 65 && first <= 90 {
		return true
	}
	return false
}

// FillFirst 填充直到长度
func FillFirst(str string, length int, char string) string {
	lstr := len(str)
	if lstr < length {
		for i := lstr; i < length; i++ {
			str = char + str
		}
	}
	return str
}

// FillLast 填充直到长度
func FillLast(str string, length int, char string) string {
	lstr := len(str)
	if lstr < length {
		for i := lstr; i < length; i++ {
			str = str + char
		}
	}
	return str
}

// LowerFirst 首字母小写
func LowerFirst(str string) string {
	first := str[:1]
	return strings.Replace(str, first, strings.ToLower(first), 1)
}

// UpperFirst 首字母大写
func UpperFirst(str string) string {
	if len(str) == 0 {
		return str
	}

	first := str[:1]

	return strings.Replace(str, first, strings.ToUpper(first), 1)
}

// DeleteExtraSpace 删除字符串中多余的空格(含tab)，有多个空格时，仅保留一个空格，同时将字符串中的tab换为空格
func DeleteExtraSpace(s string) string {
	//删除字符串中的多余空格，有多个空格时，仅保留一个空格
	s1 := strings.Replace(s, "  ", " ", -1)      //替换tab为空格
	regstr := "\\s{2,}"                          //两个及两个以上空格的正则表达式
	reg, _ := regexp.Compile(regstr)             //编译正则表达式
	s2 := make([]byte, len(s1))                  //定义字符数组切片
	copy(s2, s1)                                 //将字符串复制到切片
	spc_index := reg.FindStringIndex(string(s2)) //在字符串中搜索
	for len(spc_index) > 0 {                     //找到适配项
		s2 = append(s2[:spc_index[0]+1], s2[spc_index[1]:]...) //删除多余空格
		spc_index = reg.FindStringIndex(string(s2))            //继续在字符串中搜索
	}
	return string(s2)
}

// GetStrLength 返回输入的字符串的字数，汉字和中文标点算 1 个字数，英文和其他字符 2 个算 1 个字数，不足 1 个算 1个
func GetStrLength(str string) float64 {
	var total float64

	reg := regexp.MustCompile("/·|，|。|《|》|‘|’|”|“|；|：|【|】|？|（|）|、/")

	for _, r := range str {
		if unicode.Is(unicode.Scripts["Han"], r) || reg.Match([]byte(string(r))) {
			total = total + 1
		} else {
			total = total + 0.5
		}
	}

	return math.Ceil(total)
}
